#include "catalog.h"
#include "query.h"
#include "sort.h"
#include "index.h"
#include <string.h>
#include <stdlib.h>

// INL: Indexed-Nested Loops for evaluating joins with an index on the 
//      inner/right relation (attrdesc2)
Status Operators::INL(const string & result,          // output relation name
	              const int projCnt,              // number of attributes in the projection
                      const AttrDesc attrDescArray[], // The projection list (as AttrDesc)
                      const AttrDesc & attrDesc1,     // The left attribute in the join predicate
                      const Operator op,              // The join operation
                      const AttrDesc & attrDesc2,     // The left attribute in the join predicate
                      const int reclen)              // The lenght of a tuple in the result relation
{
    cout << "Algorithm: Indexed NL Join" << endl;
    Status ret;

    const AttrDesc *indexDesc, *scanDesc;
    if (attrDesc1.indexed)
    {
        indexDesc = &attrDesc1;
        scanDesc = &attrDesc2;
    } else
    {
        indexDesc = &attrDesc2;
        scanDesc = &attrDesc1;
    }
    
    HeapFileScan scan1(scanDesc->relName, ret);
    if (ret != OK) return ret;

    Index indexScan(indexDesc->relName, indexDesc->attrOffset, indexDesc->attrLen, 
            (Datatype)indexDesc->attrType, 0, ret);
    if (ret != OK) return ret;

    //find answers from inner scan
    HeapFileScan scan2(indexDesc->relName, ret);
    if (ret != OK) return ret;
    //put answer
    HeapFileScan ansFile(result, ret);
    if (ret != OK) return ret;

    ret = scan1.startScan(0,0, (Datatype)0,0,(Operator)0);
    if (ret != OK) return ret;


    RID rid_out, rid_in;
    Record rec_out, rec_in;
    //get record
    //flip op
    //start index scan
    //get second rec
    while(scan1.scanNext(rid_out, rec_out) == OK)
    {
        if (ret != OK) return ret;
        ret = indexScan.startScan((char*) rec_out.data + scanDesc->attrOffset);
        while(indexScan.scanNext(rid_in) == OK)
        {
            ret = scan2.getRandomRecord(rid_in, rec_in);
            if (ret != OK) return ret;
            //we have a match, must now make record and insert
            Record result;
            result.data = malloc(reclen);
            result.length = reclen;

            int recOffset = 0;
            for (int i = 0; i < projCnt; i++)
            {
                if (!strcmp(attrDescArray[i].relName, scanDesc->relName))
                {
                    memcpy((char*)result.data + recOffset, 
                        (char*) rec_out.data + (attrDescArray[i].attrOffset),
                        attrDescArray[i].attrLen);
                }
                else 
                {
                    memcpy((char*)result.data + recOffset, 
                        (char*) rec_in.data + (attrDescArray[i].attrOffset),
                        attrDescArray[i].attrLen);
                }
                recOffset += attrDescArray[i].attrLen;
            }

            RID resultRID;
            ret = ansFile.insertRecord(result, resultRID);
            if (ret != OK) return ret;
            free(result.data);
        }
        ret = indexScan.endScan();
        if (ret != OK) return ret;
    }
    ret = scan1.endScan();
    if (ret != OK) return ret;

    return OK;
}

